﻿// <file>
//     <copyright see="prj:///doc/copyright.txt"/>
//     <license see="prj:///doc/license.txt"/>
//     <owner name="Mike Krüger" email="mike@icsharpcode.net"/>
//     <version>$Revision$</version>
// </file>

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

using ICSharpCode.TextEditor.Document;

namespace ICSharpCode.TextEditor
{
	/// <summary>
	/// This class handles all mouse stuff for a textArea.
	/// </summary>
	public class TextAreaMouseHandler
	{
		TextArea  textArea;
		bool      doubleclick = false;       
		bool      clickedOnSelectedText = false;
        bool      doubleClickFindSameWord = true;
        bool      controlDoubleClickSelectFullLine = true;

        MouseButtons button;
		
		static readonly Point nilPoint = new Point(-1, -1);
		Point mousedownpos       = nilPoint;
		Point lastmousedownpos   = nilPoint;
        long lastdoubleclickTime = 0;
        bool doubleclickSelected = false;
		
		bool gotmousedown = false;
		bool dodragdrop = false;

        TextLocation minSelection = TextLocation.Empty;
        TextLocation maxSelection = TextLocation.Empty;

        public TextAreaMouseHandler(TextArea motherTextArea)
		{
			textArea = motherTextArea;
		}
		
		public void Attach()
		{
			textArea.Click       += new EventHandler(TextAreaClick);
			textArea.MouseMove   += new MouseEventHandler(TextAreaMouseMove);
			
			textArea.MouseDown   += new MouseEventHandler(OnMouseDown);
			textArea.DoubleClick += new EventHandler(OnDoubleClick);
			textArea.MouseLeave  += new EventHandler(OnMouseLeave);
			textArea.MouseUp     += new MouseEventHandler(OnMouseUp);
			textArea.LostFocus   += new EventHandler(TextAreaLostFocus);
			textArea.ToolTipRequest += new ToolTipRequestEventHandler(OnToolTipRequest);
		}

        int SubstringCount(string fullstring, string substring)
        {
            int resultCount = 0; //计数器
            if (!string.IsNullOrEmpty(fullstring) &&
                !string.IsNullOrEmpty(substring) &&
                fullstring.Contains(substring))
            {
                substring = substring.ToLower();
                fullstring = fullstring.ToLower();

                string strReplaced = fullstring.Replace(substring, "");
                resultCount = (fullstring.Length - strReplaced.Length) / substring.Length;

                //for (int i = 0; i < fullstring.Length - substring.Length; i++)
                //{
                //    string seach = fullstring.Substring(i, substring.Length);
                //    if (substring.Equals(seach + "", StringComparison.OrdinalIgnoreCase))
                //    {
                //        resultCount++;
                //    }
                //}

            }
            return resultCount;
        }

        UInt64 DateTimeToUInt64(DateTime dataTime)
        {
            return Convert.ToUInt64(dataTime.ToString("yyyyMMddHHmmssfff"));
        }

        void OnToolTipRequest(object sender, ToolTipRequestEventArgs e)
		{
			if (e.ToolTipShown)
				return;
			Point mousepos = e.MousePosition;
			FoldMarker marker = textArea.TextView.GetFoldMarkerFromPosition(mousepos.X - textArea.TextView.DrawingPosition.X,
			                                                                mousepos.Y - textArea.TextView.DrawingPosition.Y);
			if (marker != null && marker.IsFolded) {
				StringBuilder sb = new StringBuilder(marker.InnerText);
				
				// max 10 lines
				int endLines = 0;
				for (int i = 0; i < sb.Length; ++i) {
					if (sb[i] == '\n') {
						++endLines;
						if (endLines >= 10) {
							sb.Remove(i + 1, sb.Length - i - 1);
							sb.Append(Environment.NewLine);
							sb.Append("...");
							break;
							
						}
					}
				}
				sb.Replace("\t", "    ");
				e.ShowToolTip(sb.ToString());
				return;
			}
			
			List<TextMarker> markers = textArea.Document.MarkerStrategy.GetMarkers(e.LogicalPosition);
			foreach (TextMarker tm in markers) {
				if (tm.ToolTip != null) {
					e.ShowToolTip(tm.ToolTip.Replace("\t", "    "));
					return;
				}
			}
		}
		
		void ShowHiddenCursorIfMovedOrLeft()
		{
			textArea.ShowHiddenCursor(!textArea.Focused ||
			                          !textArea.ClientRectangle.Contains(textArea.PointToClient(Cursor.Position)));
		}
		
		void TextAreaLostFocus(object sender, EventArgs e)
		{
			// The call to ShowHiddenCursorIfMovedOrLeft is delayed
			// until pending messages have been processed
			// so that it can properly detect whether the TextArea
			// has really lost focus.
			// For example, the CodeCompletionWindow gets focus when it is shown,
			// but immediately gives back focus to the TextArea.
			textArea.BeginInvoke(new MethodInvoker(ShowHiddenCursorIfMovedOrLeft));
		}
		
		void OnMouseLeave(object sender, EventArgs e)
		{
			ShowHiddenCursorIfMovedOrLeft();
			gotmousedown = false;
			mousedownpos = nilPoint;
		}

        void OnMouseUp(object sender, MouseEventArgs e)
        {
            if ( e.Button == MouseButtons.Left &&
                (Control.ModifierKeys & Keys.Alt) == Keys.Alt)
            {
                Point mousepos = e.Location;
                TextLocation realmousepos = textArea.TextView.GetLogicalPosition(
                        Math.Max(0, mousepos.X - textArea.TextView.DrawingPosition.X),
                        mousepos.Y - textArea.TextView.DrawingPosition.Y);
                realmousepos = textArea.Caret.ValidatePosition(realmousepos);
                textArea.SelectionManager.SelectionEnd = realmousepos;
                textArea.SelectionManager.ExtendALTSelection();                
            }
            textArea.SelectionManager.selectFrom.where = WhereFrom.None;
            gotmousedown = false;
            mousedownpos = nilPoint;
            OnMouseClick(sender, e);
        }
		
		void TextAreaClick(object sender, EventArgs e)
		{
			Point mousepos;
			mousepos = textArea.mousepos;
			
			if (dodragdrop)
			{
				return;
			}

			if (clickedOnSelectedText && textArea.TextView.DrawingPosition.Contains(mousepos.X, mousepos.Y))
			{
				textArea.SelectionManager.ClearSelection();

				TextLocation clickPosition = textArea.TextView.GetLogicalPosition(
					mousepos.X - textArea.TextView.DrawingPosition.X,
					mousepos.Y - textArea.TextView.DrawingPosition.Y);
				textArea.Caret.Position = clickPosition;
				textArea.SetDesiredColumn();
			}
		}		
		
		void TextAreaMouseMove(object sender, MouseEventArgs e)
		{
			textArea.mousepos = e.Location;

			// honour the starting selection strategy
			switch (textArea.SelectionManager.selectFrom.where)
			{
				case WhereFrom.Gutter:
					ExtendSelectionToMouse();
					return;

				case WhereFrom.TArea:
					break;

			}
			textArea.ShowHiddenCursor(false);
			if (dodragdrop) {
				dodragdrop = false;
				return;
			}
			
			doubleclick = false;
			textArea.mousepos = new Point(e.X, e.Y);
			
			if (clickedOnSelectedText) {
				if (Math.Abs(mousedownpos.X - e.X) >= SystemInformation.DragSize.Width / 2 ||
				    Math.Abs(mousedownpos.Y - e.Y) >= SystemInformation.DragSize.Height / 2)
				{
					clickedOnSelectedText = false;
					ISelection selection = textArea.SelectionManager.GetSelectionAt(textArea.Caret.Offset);
					if (selection != null) {
						string text = selection.SelectedText;
						bool isReadOnly = SelectionManager.SelectionIsReadOnly(textArea.Document, selection);
						if (text != null && text.Length > 0) {
							DataObject dataObject = new DataObject ();
							dataObject.SetData(DataFormats.UnicodeText, true, text);
							dataObject.SetData(selection);
							dodragdrop = true;
							textArea.DoDragDrop(dataObject, isReadOnly ? DragDropEffects.All & ~DragDropEffects.Move : DragDropEffects.All);
						}
					}
				}
				
				return;
			}
			
			if (e.Button == MouseButtons.Left) {
				if (gotmousedown && textArea.SelectionManager.selectFrom.where == WhereFrom.TArea)
				{
					ExtendSelectionToMouse();
				}
			}
		}

        void ExtendSelectionToMouse()
        {
            Point mousepos;
            mousepos = textArea.mousepos;
            TextLocation realmousepos = textArea.TextView.GetLogicalPosition(
                Math.Max(0, mousepos.X - textArea.TextView.DrawingPosition.X),
                mousepos.Y - textArea.TextView.DrawingPosition.Y);
            int y = realmousepos.Y;
            realmousepos = textArea.Caret.ValidatePosition(realmousepos);
            TextLocation oldPos = textArea.Caret.Position;
            if (oldPos == realmousepos && textArea.SelectionManager.selectFrom.where != WhereFrom.Gutter)
            {
                return;
            }

            // the selection is from the gutter
            if (textArea.SelectionManager.selectFrom.where == WhereFrom.Gutter)
            {
                if (realmousepos.Y < textArea.SelectionManager.SelectionStart.Y)
                {
                    // the selection has moved above the startpoint
                    textArea.Caret.Position = new TextLocation(0, realmousepos.Y);
                }
                else
                {
                    // the selection has moved below the startpoint
                    textArea.Caret.Position = textArea.SelectionManager.NextValidPosition(realmousepos.Y);
                }
            }
            else
            {
                textArea.Caret.Position = realmousepos;
            }

            // moves selection across whole words for double-click initiated selection
            if (!minSelection.IsEmpty && textArea.SelectionManager.SelectionCollection.Count > 0 && textArea.SelectionManager.selectFrom.where == WhereFrom.TArea)
            {
                // Extend selection when selection was started with double-click
                ISelection selection = textArea.SelectionManager.SelectionCollection[0];
                TextLocation min = textArea.SelectionManager.GreaterEqPos(minSelection, maxSelection) ? maxSelection : minSelection;
                TextLocation max = textArea.SelectionManager.GreaterEqPos(minSelection, maxSelection) ? minSelection : maxSelection;
                if (textArea.SelectionManager.GreaterEqPos(max, realmousepos) && textArea.SelectionManager.GreaterEqPos(realmousepos, min))
                {
                    textArea.SelectionManager.SetSelection(min, max);
                }
                else if (textArea.SelectionManager.GreaterEqPos(max, realmousepos))
                {
                    int moff = textArea.Document.PositionToOffset(realmousepos);
                    min = textArea.Document.OffsetToPosition(FindWordStart(textArea.Document, moff));
                    textArea.SelectionManager.SetSelection(min, max);
                }
                else
                {
                    int moff = textArea.Document.PositionToOffset(realmousepos);
                    max = textArea.Document.OffsetToPosition(FindWordEnd(textArea.Document, moff));
                    textArea.SelectionManager.SetSelection(min, max);
                }
            }
            else
            {
                //if((Control.ModifierKeys & Keys.Alt)!=0)
                if ((Control.ModifierKeys & Keys.Alt) == Keys.Alt)
                {
                    textArea.SelectionManager.IsMutilSelect = true;
                    textArea.SelectionManager.SelectionEnd = textArea.Caret.Position;
                    textArea.SelectionManager.ExtendALTSelection();
                }
                else
                {
                    textArea.SelectionManager.ExtendSelection(oldPos, textArea.Caret.Position);
                }                    
            }
            textArea.SetDesiredColumn();
        }
		
        /// <summary>
        /// find same words when mouse bouble click
        /// </summary>
		void DoubleClickSelectionExtend()
		{
			Point mousepos;
			mousepos = textArea.mousepos;
			
			textArea.SelectionManager.ClearSelection();
			if (textArea.TextView.DrawingPosition.Contains(mousepos.X, mousepos.Y))
			{
				FoldMarker marker = textArea.TextView.GetFoldMarkerFromPosition(mousepos.X - textArea.TextView.DrawingPosition.X,
				                                                                mousepos.Y - textArea.TextView.DrawingPosition.Y);
                if (marker != null && marker.IsFolded)
                {
                    marker.IsFolded = false;
                    textArea.MotherTextAreaControl.AdjustScrollBars();
                    textArea.Document.GuidelinesManager.Update(textArea);

                    if (textArea.Document.TextEditorProperties.EnableFolding && textArea.Document.FoldingManager != null)
                        textArea.Document.FoldingManager.NotifyFoldingsChanged(EventArgs.Empty);

                    return;
                }
                if (textArea.Caret.Offset < textArea.Document.TextLength)
                {
                    switch (textArea.Document.GetCharAt(textArea.Caret.Offset))
                    {
                        case '"':
                            if (textArea.Caret.Offset < textArea.Document.TextLength)
                            {
                                int next = FindNext(textArea.Document, textArea.Caret.Offset + 1, '"');
                                minSelection = textArea.Caret.Position;
                                if (next > textArea.Caret.Offset && next < textArea.Document.TextLength)
                                    next += 1;
                                maxSelection = textArea.Document.OffsetToPosition(next);
                            }
                            break;
                        default:
                            minSelection = textArea.Document.OffsetToPosition(FindWordStart(textArea.Document, textArea.Caret.Offset));
                            maxSelection = textArea.Document.OffsetToPosition(FindWordEnd(textArea.Document, textArea.Caret.Offset));
                            break;

                    }
                    textArea.Caret.Position = maxSelection;
                    textArea.SelectionManager.ExtendSelection(minSelection, maxSelection);
                }

                if (textArea.SelectionManager.selectionCollection.Count > 0)
                {
                    ISelection selection = textArea.SelectionManager.selectionCollection[0];

                    selection.StartPosition = minSelection;
                    selection.EndPosition = maxSelection;
                    textArea.SelectionManager.SelectionStart = minSelection;
                }

                if (doubleClickFindSameWord)
                {
                    string contentText = textArea.Document.TextContent;
                    string selecteText = textArea.SelectionManager.SelectedText;

                    if (string.IsNullOrEmpty(selecteText))
                        selecteText = selecteText.Replace("\t", "").Trim();

                    ISelection currentSelection = null;
                    if (textArea.SelectionManager.SelectionCollection != null
                        && textArea.SelectionManager.SelectionCollection.Count > 0)
                    {
                        currentSelection = textArea.SelectionManager.SelectionCollection[0];
                    }

                    int index = 0;
                    int count = 0;
                    TextLocation startPoint, endPoint;
                    int total = SubstringCount(contentText, selecteText);

                    textArea.SelectionManager.ClearSelection();

                    StringComparison comparisonType = StringComparison.OrdinalIgnoreCase;
                    while (count < total &&
                        index >= 0)
                    {
                        count += 1;
                        index = contentText.IndexOf(selecteText, index, comparisonType);

                        if (index < 0)
                            continue;

                        startPoint = textArea.Document.OffsetToPosition(index);
                        index = index + selecteText.Length;
                        endPoint = textArea.Document.OffsetToPosition(index);

                        DefaultSelection selection = new DefaultSelection(textArea.Document, startPoint, endPoint);

                        if (currentSelection != null)
                        {
                            if (selection.StartPosition == currentSelection.StartPosition &&
                                selection.EndPosition == currentSelection.EndPosition)
                            {
                                selection.IsCurrent = true;
                            }                          
                        }

                        textArea.SelectionManager.SelectionCollection.Add(selection);

                    }

                    //doubleclickSelected = true;

                }

                doubleclickSelected = true;

                // after a double-click selection, the caret is placed correctly,
                // but it is not positioned internally.  The effect is when the cursor
                // is moved up or down a line, the caret will take on the column first
                // clicked on for the double-click
                textArea.SetDesiredColumn();

				// HACK WARNING !!!
				// must refresh here, because when a error tooltip is showed and the underlined
				// code is double clicked the textArea don't update corrctly, updateline doesn't
				// work ... but the refresh does.
				// Mike
				textArea.Refresh();
			}

            lastdoubleclickTime = Convert.ToInt64(DateTime.Now.ToString("yyMMddHHmmssfff"));

        }

        /// <summary>
        /// select full line when mouse three click 
        /// </summary>
        void ThreeClickSelectionExtend()
        {
            Point mousepos;
            mousepos = textArea.mousepos;

            textArea.SelectionManager.ClearSelection();

            if (textArea.TextView.DrawingPosition.Contains(mousepos.X, mousepos.Y))
            {
                int line = textArea.Caret.Line;
                LineSegment lineSegment = textArea.Document.GetLineSegment(line);

                if (lineSegment.LineNumber < textArea.Document.TotalNumberOfLines - 1)
                {
                    minSelection = textArea.Document.OffsetToPosition(FindWordStart(textArea.Document, lineSegment.Offset));
                    maxSelection = textArea.Document.OffsetToPosition(FindWordEnd(textArea.Document, lineSegment.Offset + lineSegment.Length));
                }
                else
                {
                    minSelection = textArea.Document.OffsetToPosition(FindWordStart(textArea.Document, lineSegment.Offset));
                    maxSelection = textArea.Document.OffsetToPosition(FindWordEnd(textArea.Document, lineSegment.Offset + lineSegment.Length));
                }

                textArea.Caret.Position = maxSelection;
                textArea.SelectionManager.ExtendSelection(minSelection, maxSelection);
            }

        }

        void OnMouseDown(object sender, MouseEventArgs e)
        {
            Point mousepos;
            textArea.mousepos = e.Location;
            mousepos = e.Location;

            if (textArea.SelectionManager.IsMutilSelect)
            {
                if (textArea.SelectionManager.selectionCollection.Count > 0)
                {
                    textArea.SelectionManager.ClearSelection();
                }
                else
                {
                    textArea.SelectionManager.ClearMutilSelect();
                }
                textArea.SelectionManager.IsMutilSelect = false;
            }            

            if (dodragdrop)
            {
                return;
            }          

            if (doubleclick)
            {
                doubleclick = false;
                return;
            }            

            if (textArea.TextView.DrawingPosition.Contains(mousepos.X, mousepos.Y))
            {
                gotmousedown = true;
                textArea.SelectionManager.selectFrom.where = WhereFrom.TArea;
                button = e.Button;

                long clickTime = Convert.ToInt64(DateTime.Now.ToString("yyMMddHHmmssfff"));

                //当双击选择单词后连续单击选中全行
                if (button == MouseButtons.Left &&
                    doubleclickSelected &&
                    textArea.SelectionManager.SelectionCollection.Count > 0 &&
                    clickTime - lastdoubleclickTime < 600)
                {
                    doubleclickSelected = false;
                    //var iSelection = textArea.SelectionManager.SelectionCollection.Find(w => w.IsCurrent == true);                     
                    var caretLocation = textArea.Caret.Position;
                    var mouseLocation = textArea.TextView.GetLogicalPosition(e.Location);
                    if (//iSelection != null &&
                        caretLocation.Line == mouseLocation.Line)
                    {
                        ThreeClickSelectionExtend();
                        lastmousedownpos = new Point(e.X, e.Y);
                        if (textArea.SelectionManager.selectFrom.where == WhereFrom.Gutter)
                        {
                            if (!minSelection.IsEmpty && !maxSelection.IsEmpty && textArea.SelectionManager.SelectionCollection.Count > 0)
                            {
                                textArea.SelectionManager.SelectionCollection[0].StartPosition = minSelection;
                                textArea.SelectionManager.SelectionCollection[0].EndPosition = maxSelection;
                                textArea.SelectionManager.SelectionStart = minSelection;

                                minSelection = TextLocation.Empty;
                                maxSelection = TextLocation.Empty;
                            }
                        }
                        return;
                    }
                }

                //control + double-click impl three click event
                if (button == MouseButtons.Left &&
                    e.Clicks == 2 &&
                    controlDoubleClickSelectFullLine &&
                    (Control.ModifierKeys & Keys.Control) != 0)
                {
                    ThreeClickSelectionExtend();
                    lastmousedownpos = new Point(e.X, e.Y);

                    if (textArea.SelectionManager.selectFrom.where == WhereFrom.Gutter)
                    {
                        if (!minSelection.IsEmpty && !maxSelection.IsEmpty && textArea.SelectionManager.SelectionCollection.Count > 0)
                        {
                            textArea.SelectionManager.SelectionCollection[0].StartPosition = minSelection;
                            textArea.SelectionManager.SelectionCollection[0].EndPosition = maxSelection;
                            textArea.SelectionManager.SelectionStart = minSelection;

                            minSelection = TextLocation.Empty;
                            maxSelection = TextLocation.Empty;
                        }
                    }
                    return;

                }

                // double-click
                else
                if (button == MouseButtons.Left && e.Clicks == 2)
                {
                    int deltaX = Math.Abs(lastmousedownpos.X - e.X);
                    int deltaY = Math.Abs(lastmousedownpos.Y - e.Y);
                    if (deltaX <= SystemInformation.DoubleClickSize.Width &&
                        deltaY <= SystemInformation.DoubleClickSize.Height)
                    {
                        DoubleClickSelectionExtend();
                        lastmousedownpos = new Point(e.X, e.Y);

                        if (textArea.SelectionManager.selectFrom.where == WhereFrom.Gutter)
                        {
                            if (!minSelection.IsEmpty && !maxSelection.IsEmpty && textArea.SelectionManager.SelectionCollection.Count > 0)
                            {
                                textArea.SelectionManager.SelectionCollection[0].StartPosition = minSelection;
                                textArea.SelectionManager.SelectionCollection[0].EndPosition = maxSelection;
                                textArea.SelectionManager.SelectionStart = minSelection;

                                minSelection = TextLocation.Empty;
                                maxSelection = TextLocation.Empty;
                            }
                        }
                        return;

                    }
                }


                minSelection = TextLocation.Empty;
                maxSelection = TextLocation.Empty;

                lastmousedownpos = mousedownpos = new Point(e.X, e.Y);

                if (button == MouseButtons.Left)
                {
                    FoldMarker marker = textArea.TextView.GetFoldMarkerFromPosition(mousepos.X - textArea.TextView.DrawingPosition.X,
                                                                                    mousepos.Y - textArea.TextView.DrawingPosition.Y);
                    if (marker != null && marker.IsFolded)
                    {
                        if (textArea.SelectionManager.HasSomethingSelected)
                        {
                            clickedOnSelectedText = true;
                        }

                        TextLocation startLocation = new TextLocation(marker.StartColumn, marker.StartLine);
                        TextLocation endLocation = new TextLocation(marker.EndColumn, marker.EndLine);
                        textArea.SelectionManager.SetSelection(new DefaultSelection(textArea.TextView.Document, startLocation, endLocation));
                        textArea.Caret.Position = startLocation;
                        textArea.SetDesiredColumn();
                        textArea.Focus();
                        return;
                    }

                    if ((Control.ModifierKeys & Keys.Alt) == Keys.Alt)
                    {
                        textArea.SelectionManager.IsMutilSelect = true;

                        if (textArea.SelectionManager.HasSomethingSelected)
                        {
                            textArea.SelectionManager.ClearWithoutUpdate();
                        }

                        TextLocation realmousepos = textArea.TextView.GetLogicalPosition(
                            Math.Max(0, mousepos.X - textArea.TextView.DrawingPosition.X),
                            mousepos.Y - textArea.TextView.DrawingPosition.Y);
                        realmousepos = textArea.Caret.ValidatePosition(realmousepos);
                        textArea.SelectionManager.SelectionStart = realmousepos;                        
                    }
                    else
                    {
                        if ((Control.ModifierKeys & Keys.Shift) == Keys.Shift)
                        {
                            ExtendSelectionToMouse();
                        }
                        else
                        {
                            TextLocation realmousepos = textArea.TextView.GetLogicalPosition(mousepos.X - textArea.TextView.DrawingPosition.X, mousepos.Y - textArea.TextView.DrawingPosition.Y);
                            clickedOnSelectedText = false;

                            int offset = textArea.Document.PositionToOffset(realmousepos);

                            if (textArea.SelectionManager.HasSomethingSelected &&
                                textArea.SelectionManager.IsSelected(offset))
                            {
                                clickedOnSelectedText = true;
                            }
                            else
                            {
                                textArea.SelectionManager.ClearSelection();
                                if (mousepos.Y > 0 && mousepos.Y < textArea.TextView.DrawingPosition.Height)
                                {
                                    TextLocation pos = new TextLocation();
                                    pos.Y = Math.Min(textArea.Document.TotalNumberOfLines - 1, realmousepos.Y);
                                    pos.X = realmousepos.X;
                                    textArea.Caret.Position = pos;
                                    textArea.SetDesiredColumn();
                                }
                            }
                        }
                    }

                    
                }
                else if (button == MouseButtons.Right)
                {
                    // Rightclick sets the cursor to the click position unless
                    // the previous selection was clicked
                    TextLocation realmousepos = textArea.TextView.GetLogicalPosition(mousepos.X - textArea.TextView.DrawingPosition.X, mousepos.Y - textArea.TextView.DrawingPosition.Y);
                    int offset = textArea.Document.PositionToOffset(realmousepos);
                    if (!textArea.SelectionManager.HasSomethingSelected ||
                        !textArea.SelectionManager.IsSelected(offset))
                    {
                        textArea.SelectionManager.ClearSelection();
                        if (mousepos.Y > 0 && mousepos.Y < textArea.TextView.DrawingPosition.Height)
                        {
                            TextLocation pos = new TextLocation();
                            pos.Y = Math.Min(textArea.Document.TotalNumberOfLines - 1, realmousepos.Y);
                            pos.X = realmousepos.X;
                            textArea.Caret.Position = pos;
                            textArea.SetDesiredColumn();
                        }
                    }                    
                }              

            }

            textArea.Focus();
            
        }
		
		int FindNext(IDocument document, int offset, char ch)
		{
			LineSegment line = document.GetLineSegmentForOffset(offset);
			int         endPos = line.Offset + line.Length;
			
			while (offset < endPos && document.GetCharAt(offset) != ch) {
				++offset;
			}
			return offset;
		}
		
		bool IsSelectableChar(char ch)
		{
            //return Char.IsLetterOrDigit(ch) || ch=='_';
            return ch == '$' || ch == '@' || ch == '_' || Char.IsLetterOrDigit(ch);
        }
		
		int FindWordStart(IDocument document, int offset)
		{
			LineSegment line = document.GetLineSegmentForOffset(offset);
			
			if (offset > 0 && Char.IsWhiteSpace(document.GetCharAt(offset - 1)) && Char.IsWhiteSpace(document.GetCharAt(offset))) {
				while (offset > line.Offset && Char.IsWhiteSpace(document.GetCharAt(offset - 1))) {
					--offset;
				}
			} else  if (IsSelectableChar(document.GetCharAt(offset)) || (offset > 0 && Char.IsWhiteSpace(document.GetCharAt(offset)) && IsSelectableChar(document.GetCharAt(offset - 1))))  {
				while (offset > line.Offset && IsSelectableChar(document.GetCharAt(offset - 1))) {
					--offset;
				}
			} else {
				if (offset > 0 && !Char.IsWhiteSpace(document.GetCharAt(offset - 1)) && !IsSelectableChar(document.GetCharAt(offset - 1)) ) {
					return Math.Max(0, offset - 1);
				}
			}
			return offset;
		}
		
		int FindWordEnd(IDocument document, int offset)
		{
			LineSegment line   = document.GetLineSegmentForOffset(offset);
			if (line.Length == 0)
				return offset;
			int         endPos = line.Offset + line.Length;
			offset = Math.Min(offset, endPos - 1);
			
			if (IsSelectableChar(document.GetCharAt(offset)))  {
				while (offset < endPos && IsSelectableChar(document.GetCharAt(offset))) {
					++offset;
				}
			} else if (Char.IsWhiteSpace(document.GetCharAt(offset))) {
				if (offset > 0 && Char.IsWhiteSpace(document.GetCharAt(offset - 1))) {
					while (offset < endPos && Char.IsWhiteSpace(document.GetCharAt(offset))) {
						++offset;
					}
				}
			} else {
				return Math.Max(0, offset + 1);
			}
			
			return offset;
		}	
		
		void OnDoubleClick(object sender, System.EventArgs e)
		{
			if (dodragdrop) {
				return;
			}			
			textArea.SelectionManager.selectFrom.where = WhereFrom.TArea;
			doubleclick = true;			
		}

        void OnMouseClick(object sender, System.EventArgs e)
        {
            if (((MouseEventArgs)e).Button == MouseButtons.Right)
                textArea.DoShowContextMenuHandler(e);
        }

	}
}
